<?php

namespace common\service;

use common\exception\LogicException;
use common\model\OrderTaskListModel;
use common\model\ProjectModel;
use common\model\ReviewRequestModel;
use common\model\ReviewRequestNodeModel;
use common\model\StatusModel;
use common\model\EntityModel;
use common\model\TaskModel;
use common\model\TaskWorkOrderModel;
use common\model\VersionModel;
use common\service\task_deprecated\StepAttributeChangeHandler;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\Hook;
use Webman\Stomp\Client;

class TaskAbolitionService
{

    use SingletonTrait;

    /**
     * 处理审批中的任务
     * @throws Exception
     */
    public function execSubmitted($taskList)
    {
        if (empty($taskList)) {
            return;
        }
        $linkId = [];
        $status = StatusService::getInstance()->getOne(['code' => 'submitted'], '*')['id'];
        foreach ($taskList as $v) {
            $json = json_decode($v['json'], true);
            $taskStatus = $json['task_status'];
            if ($taskStatus == $status) {
                $linkId[] = $v['id'];
            }
        }
        if (empty($linkId)) {
            return;
        }
        // 查询当前任务是否审批中,审批中的任务,自动更改为不通过
        $this->notThrough($linkId);
    }


    /**
     * 不通过审核
     * @param $linkId
     * @throws Exception
     */
    public function notThrough($linkId)
    {
        // 获取最新提交审核的审核版本
        $versionModel = model(VersionModel::class)
            ->where([
                'link_id' => ['IN', $linkId],
                'module_id' => module_by_code('task')['id']
            ])
            ->field('id,link_id')->select();
        if (!empty($versionModel)) {
            $linkData = [];
            foreach ($versionModel as $v) {
                $linkData[$v['link_id']][] = $v['id'];
            }
            $reviewRequestLinkId = [];
            // 处理最新提交审核的审核版本id
            foreach ($linkData as $val) {
                $reviewRequestLinkId[] = max($val);
            }
        }
        // 查询当前审核版本的审批节点
        if (!empty($reviewRequestLinkId)) {
            $reviewRequestModel = model(ReviewRequestModel::class)
                ->where([
                    'link_id' => ['IN', $reviewRequestLinkId],
                    'module_id' => module_by_code('version')['id'],
                ])
                ->field('id')->select();
            $reviewId = array_column($reviewRequestModel, 'id');
        }
        if (!empty($reviewId)) {
            $reviewRequestNode = model(ReviewRequestNodeModel::class)
                ->field('id,review_request_id,param,is_reviewed')
                ->where(['review_request_id' => ['IN', $reviewId]])->select();
        }
        // 修改节点审批状态
        if (!empty($reviewRequestNode)) {
            $this->updateReviewRequestNode($reviewRequestNode);
        }
    }


    /**
     * 修改当前审批节点状态为不通过
     * @param $reviewRequestNode
     * @return bool
     * @throws Exception
     */
    public function updateReviewRequestNode($reviewRequestNode)
    {
        // 组织审批不通过数据
        $updData = [];
        $updateReviewRequestList = [];
        if (!empty($reviewRequestNode)) {
            foreach ($reviewRequestNode as $val) {
                if ($val['is_reviewed'] == 'yes') {
                    continue;
                }
                if (!empty($val['param'])) {
                    continue;
                }
                // 审核申请节点更新
                $updData[] = [
                    'id' => $val['id'],
                    'is_pass' => 'no', // 是否通过
                    'is_active' => 'no', // 是否激活
                    'is_reviewed' => 'yes', // 是否审核
                    'is_second_confirm' => 'yes', // 二次确认通过
                    'is_abolition' => 'yes', // 是否废除
                ];

                // 审核申请更新
                $updateReviewRequestList[$val['review_request_id']] = [
                    'id' => $val['review_request_id'],
                    'is_pass' => "no",
                    'is_reviewed' => "yes",
                    'reviewed' => time(),
                ];
            }
        }
        if (!empty($updData)) {
            CommonService::instance('review_request_node')->commonBatchUpdate($updData);
        }
        if (!empty($updateReviewRequestList)) {
            CommonService::instance('review_request')->commonBatchUpdate(array_values($updateReviewRequestList));
        }
        return true;
    }

    /**
     * 获取任务制作状态
     * @param $projectId
     * @param $entityId
     * @param $taskList
     * @return string
     */
    public function getTaskStatus($projectId, $entityId, &$taskList): string
    {
        // 内部任务制作状态
        $taskList = model(TaskModel::class)
            ->field('id,json,tenant_id,executor_tenant_id,is_assignee,assign_status')
            ->where(['project_id' => $projectId, 'entity_id' => ['IN', $entityId]])
            ->select();
        if (empty($taskList)) {
            return false;
        }

        $statusList = model(StatusModel::class)->where(['correspond' => 'not_started', 'code' => 'closed', '_logic' => 'OR'])->select();
        $notStartedId = [];
        $closedId = null;
        foreach ($statusList as $statusItem) {
            if ($statusItem['correspond'] == 'not_started') {
                $notStartedId[] = $statusItem['id'];
            }
            if ($statusItem['code'] == 'closed') {
                $closedId = $statusItem['id'];
            }
        }

        $status = false;
        //判定是否有还在制作的任务
        foreach ($taskList as $taskItem) {
            $taskJson = json_decode($taskItem['json'], true);
            if (empty($taskJson['task_status'])) {
                continue;
            }
            $taskStatus = $taskJson['task_status'];

            //如果是取消状态,判定之前是否做过
            if ($closedId == $taskStatus) {
                //废弃前的状态
                if (!in_array($taskJson['task_deprecate_data']['task_status'] ?? 0, $notStartedId)) {
                    $status = true;
                }
            } elseif (!in_array($taskStatus, $notStartedId)) {
                $status = true;
            }
        }

        // 查询出外包任务 追加到任务列表里
        $taskIdList = array_column($taskList, 'id');
        $orderTaskList = OrderService::getInstance()->getOrderTaskListByTaskIdList($taskIdList, ['IN', [
            OrderTaskListModel::STATUS_DEFAULT,
            OrderTaskListModel::STATUS_INVALID,
            OrderTaskListModel::STATUS_WITHDRAW,
        ]]);
        if (!empty($orderTaskList)) {
            $realTaskIds = array_column($orderTaskList, 'real_task_id');
            $realTaskList = model(TaskModel::class)->where([
                'id' => ["IN", $realTaskIds]
            ])->select();
            $taskList = array_merge($taskList, $realTaskList);
        }


        return $status;
    }


    /**
     * 更改任务状态
     * @param $status
     * @param $taskList
     * @return array
     * @throws Exception
     */
    public function setTaskStatus($status, $taskList)
    {
        if (empty($taskList)) {
            return [];
        }
        // 组织更改状态数据
        $updateData = [];
        $taskStatus = StatusService::getInstance()->getOne(['code' => $status], '*')['id'] ?? '';
        $statusSubmittedId = StatusService::getInstance()->getOne(['code' => 'submitted'], '*')['id'];
        $statusWaitReviewId = StatusService::getInstance()->getTaskWaitForPartyAReviewStatus()['id'];
        $statusNotPassId = StatusService::getInstance()->getTaskReviewRejectStatus()['id'];
        foreach ($taskList as $v) {
            $jsonArr = json_decode($v['json'], true);
            if ($jsonArr['task_status'] == $taskStatus) {
                // 已经被废除了 就跳过
                continue;
            }

            if (isset($jsonArr['is_dismantle_task']) && (boolean)$jsonArr['is_dismantle_task'] == true && $status == 'closed') {
                // 如果是子任务 并且当前为废除操作时 则直接将该任务设置为已取消状态
                $jsonArr['task_status'] = $taskStatus;
            } elseif (isset($jsonArr['task_status'])) {
                if (in_array($jsonArr['task_status'], [$statusSubmittedId, $statusWaitReviewId])) {
                    $jsonArr['task_status'] = $statusNotPassId;
                }
            }

            // 废除功能,旧数据
            $jsonArr['task_deprecate_data'] = $jsonArr;
            $jsonArr['task_status'] = $taskStatus;
            $tmpUpdateData = [
                'id' => $v['id'],
                'json' => $jsonArr,
            ];

            //废除之后未分配的不能再分配
            if ($v['assign_status'] == TaskModel::ASSIGN_STATUS_DEFAULT) {
                $tmpUpdateData['assign_status'] = TaskModel::ASSIGN_STATUS_REJECTED;
            }
            $updateData[] = $tmpUpdateData;
        }
        if (empty($updateData)) {
            return [];
        }
        return CommonService::instance('task')->commonBatchUpdate($updateData);
    }

    /**
     * 删除清单
     * @param $entityId
     * @return false|float|int|mixed|string
     */
    public function removeEntity($entityId)
    {
        if (empty($entityId)) {
            throw new LogicException('delete entity_id is null', ErrorCode::DELETE_ENTITY_FAIL);
        }
        // 删除清单
        return model(EntityModel::class)->where(['id' => ['IN', $entityId]])->delete();
    }


    /**
     * 删除任务
     * @param $taskList
     * @return false|float|int|mixed|string|void
     */
    public function removeTask($taskList)
    {
        if (empty($taskList)) {
            return;
        }
        $deleteId = array_column($taskList, 'id');
        return model(TaskModel::class)->where(['id' => ['IN', $deleteId]])->delete();
    }

    /**
     * 修改工单状态为已失效
     * @param $taskList
     * @param $status
     * @return void
     * @throws \Exception
     */
    public function setTaskWorkStatus($taskList, $status)
    {
        $taskIdList = [];
        foreach ($taskList as $value) {
            $taskIdList[] = $value['id'];
        }
        if (empty($taskIdList)) {
            return;
        }
        $isWorkOrder = model(TaskWorkOrderModel::class)->where(['task_id' => ['IN', $taskIdList]])->find();
        if (empty($isWorkOrder)) {
            return;
        }
        model(TaskWorkOrderModel::class)->where(['task_id' => ['IN', $taskIdList]])->save(['status' => $status]);
    }

    /**
     * 推送会话消息
     * @param $taskList
     * @param $status
     * @return array|void
     */
    public function pushWorkOrderChatMessage($taskList, $status)
    {
        $taskIds = array_column($taskList, 'id');
        $taskWorkChatList = model(TaskWorkOrderModel::class)
            ->join("task_work_order_user on task_work_order.id = task_work_order_user.work_order_id")
            ->join("user u on task_work_order_user.user_id = u.id")
            ->field('task_work_order.number,task_work_order_user.user_id,task_work_order.chat_global_id,u.union_id')
            ->where(['task_work_order.task_id' => ['IN', $taskIds]])
            ->where("task_work_order.status != {$status} and task_work_order.chat_global_id !=''")
            ->select();
        if (empty($taskWorkChatList)) {
            return [];
        }
        $chatList = [];
        foreach ($taskWorkChatList as $value) {
            $chatList[$value['chat_global_id']][] = $value;
        }
        $chatData = [];
        foreach ($chatList as $k => $chatValue) {
            $receiver = array_column($chatValue, 'union_id');
            $chatData[] = [
                'chat_global_id' => $k, 'receiver' => $receiver, 'content_type' => 'change_work_order_chat_status',
                'status' => $status
            ];
        }
        // 发送废除状态到消息盒子
        teamones_request('teamones-im', 'message/push_batch_work_order_chat_message', ["data" => $chatData]);
    }

    /**
     * 批量解散工单会话群
     * @param $taskList
     * @return void
     */
    public function batchDisbandChat($taskList)
    {
        if (empty($taskList)) {
            return;
        }
        $taskIds = array_column($taskList, 'id');
        $taskWorkChatList = model(TaskWorkOrderModel::class)
            ->join("task_work_order_user on task_work_order.id = task_work_order_user.work_order_id")
            ->join("user u on task_work_order_user.user_id = u.id")
            ->field('task_work_order.number,task_work_order_user.user_id,task_work_order.chat_global_id,u.union_id')
            ->where(['task_work_order.task_id' => ['IN', $taskIds]])
            ->where("task_work_order.chat_global_id !=''")
            ->select();
        if (empty($taskWorkChatList)) {
            return;
        }
        $chatGlobalIds = array_column($taskWorkChatList, 'chat_global_id');
        // 发送废除状态到消息盒子
        $requestData = [
            "param" => [
                'filter' => [
                    'global_id' => ['-in', join(',', $chatGlobalIds)],
                ],
            ],
        ];
        teamones_request('teamones-im', 'chat/bath_disband_chat', $requestData);
    }

    /**
     * 查询实体贴图待办任务
     * @param $entity
     * @return array|false|mixed|string
     */
    public function getEntityTexTodoTask($entity)
    {
        $filter = [
            'task.project_id' => $entity['project_id'],
            'task.entity_module_id' => module_by_code('todo')['id'],
            'task.entity_id' => $entity['id'],
            'task.step_type' => TaskModel::STEP_TYPE_ENTITY_TO_DO,
        ];
        return model(TaskModel::class)->where($filter)->select();
    }

    /**
     * 取消任务
     * @param array $taskList
     * @param $isEnable
     * @param int $userId
     * @param string $eventType
     * @return array
     * @throws \Throwable
     */
    public function taskClose(array $taskList, $isEnable, int $userId, $eventType = 'task_close')
    {
        model(TaskModel::class)->startTrans();
        try {
            if ($isEnable) {
                $res = TaskEnableService::getInstance()->recoveryTask($taskList);
            } else {
                // 废除
                $res = $this->setTaskStatus('closed', $taskList);
                // 处理审批中的任务
                $this->execSubmitted($taskList);
                // 发送工单会话消息
                $this->pushWorkOrderChatMessage($taskList, TaskWorkOrderModel::STATUS_EXPIRED);
                // 更改工单状态
                $this->setTaskWorkStatus($taskList, TaskWorkOrderModel::STATUS_EXPIRED);
            }
            // 出了分配撤回 其他废除任务都需要修改实体的属性
            if ($eventType !== 'assign_withdraw') {
                // 设置实体属性
                $this->setEntityAttribute($taskList, $isEnable);
            }
            foreach ($taskList as $task) {
                $eventData = [
                    'task_id' => $task['id'],
                    'task' => $task,
                    'operate' => $isEnable ? 'enable' : 'disable',
                    'operate_at' => time(),
                    'operator' => $userId,
                    'event_type' => $eventType,
                ];
                Hook::listen('task_closed_operate', $eventData);
                Client::send("task_close_operate_async_send_producer_message", build_queue_data_with_xu($eventData));
            }
            model(TaskModel::class)->commit();
            return $res;
        } catch (\Throwable $e) {
            model(TaskModel::class)->rollback();
            throw $e;
        }
    }

    /**
     * 废除
     * @param int $taskId
     * @param bool $isEnable
     * @param int $userId
     * @return array
     * @throws \Throwable
     */
    public function deprecated(int $taskId, bool $isEnable, int $userId)
    {
        $taskSource = model(TaskModel::class)->find($taskId);
        $taskList = [$taskSource];

        // 废除任务 支持内外部的任务一起废除
        if (in_array($taskSource['executor_type'], TaskModel::OUTSIDE_EXECUTE_TYPE_GROUP)) {
            // 任务被外包
            $realTask = OrderService::getInstance()->getOutsideTaskByTaskId($taskId);
            if (!empty($realTask)) {
                $taskList[] = $realTask;
            }
        } else {
            // 任务是外包项目
            $project = model(ProjectModel::class)->find($taskSource['project_id']);
            if ($project['type'] == ProjectModel::TYPE_OUTSOURCE) {
                $sourceProjectTask = OrderService::getInstance()->getSourceTaskByTaskId($taskId);
                if (!empty($sourceProjectTask)) {
                    $taskList[] = $sourceProjectTask;
                }
            }
        }

        //获取任务--已取消状态
        $taskStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();

        $task = CommonService::appendJsonFields($taskSource, 'json');
        if ($isEnable) {
            //判断是否已取消
            if ($task['task_status'] != $taskStatus['id']) {
                throw new LogicException("task did`nt be deprecated", ErrorCode::TASK_STATUS_UPDATE_EXISTS);
            }
        } else {
            //判断是否已废除--已取消状态
            if ($task['task_status'] == $taskStatus['id']) {
                throw new LogicException("task already be deprecated", ErrorCode::TASK_STATUS_UPDATE_EXISTS);
            }
        }
        // 提前解析json数据出来
        $taskList = array_map(function ($i) {
            return CommonService::appendJsonFields($i, 'json', false);
        }, $taskList);

        return $this->taskClose($taskList, $isEnable, $userId);
    }

    /**
     * 设置实体属性
     * @param array $taskList
     * @param bool $enable
     * @return void
     */
    private function setEntityAttribute(array $taskList, bool $enable)
    {
        /**
         * 1. 根据要废除/启用的任务 解析出实体id 和实体和废除/启用工序的关系
         * 2. 查询实体下的所有任务
         * 3. 开始根据实体来进行属性变更
         */
        $entityIdList = [];
        $entityStepCodeMap = [];
        foreach ($taskList as $task) {
            $entityIdList[$task['entity_id']] = $task['entity_id'];
            $entityStepCodeMap[$task['entity_id']] = $task['step_id'];
        }
        $taskListFields = [
            'task.id',
            'task.name',
            'task.code',
            'task.entity_module_id',
            'task.json',
            'entity.id',
            'entity.module_id',
            'entity.project_id',
            'entity.name',
            'entity.code',
            'entity.initial_episode_code',
            'entity.showings_number',
            'entity.json',
        ];

        // 查询要废除的实体下的所有工序任务
        $insideEntityTaskList = model(EntityModel::class)
            ->join('project on project.id = entity.project_id')
            ->join('task on task.entity_id = entity.id')
            ->where([
                'entity.id' => ['IN', implode(',', $entityIdList)],
                'project.type' => ProjectModel::TYPE_INSOURCE,
                'task.step_type' => TaskModel::STEP_TYPE_STEP,
            ])
            ->field(build_complex_query_fields($taskListFields, '__'))
            ->select();

        $insideTaskList = [];
        $insideEntityList = [];
        foreach ($insideEntityTaskList as $t) {
            $t = separate_complex_query_data($t, '__');
            $t['entity'] = CommonService::appendJsonFields($t['entity']);
            $t['task'] = CommonService::appendJsonFields($t['task']);
            $insideEntityList[$t['entity']['id']] = $t['entity'];
            $insideTaskList[$t['entity']['id']][] = $t['task'];
        }

        // 循环处理每个实体的工序任务
        foreach ($insideTaskList as $entityId => $insideEntityTaskList) {
            $entity = $insideEntityList[$entityId];
            // 获取要启用/废除的工序code
            $stepId = $entityStepCodeMap[$entityId] ?? 0;
            if (empty($stepId)) {
                continue;
            }
            if ($enable) {
                $attributeChanged = StepAttributeChangeHandler::getInstance()->enableAttrChanged($insideEntityTaskList, $stepId);
            } else {
                $attributeChanged = StepAttributeChangeHandler::getInstance()->disabledAttrChanged($insideEntityTaskList, $stepId);
            }
            if (empty($attributeChanged)) {
                continue;
            }
            $entityList = EntityService::getInstance()->getEntityScoped($entity);
            foreach ($entityList as $entity) {
                $module = module_by_id($entity['module_id']);
                $u = '';
                foreach ($attributeChanged as $k => $v) {
                    $u = ",'$.{$module['code']}$k','$v'";
                }
                $u = trim($u, ',');
                APP_DEBUG && trace("update entity set json = json_set(json,$u) where id = {$entity['id']}", 'DEBUG');
                model(EntityModel::class)->execute("update entity set json = json_set(json,$u) where id = {$entity['id']}");
            }
        }
    }
}
